/**
 * Xinfei.com Inc.
 * Copyright (c) 2004-2023 All Rights Reserved.
 */
package com.xinfei.techplayprod.biz.log;

import cn.hutool.core.date.DateUtil;
import com.xinfei.techplayprod.biz.util.TechplayStringUtil;
import com.xinfei.xfframework.common.ErrorContext;
import com.xinfei.xfframework.common.JsonUtil;
import com.xinfei.xfframework.context.XFRpcUtil;
import lombok.Setter;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
 * 摘要日志基类
 *
 * @author Jinyan.Huang
 * @version $ BaseDigestLog, v 0.1 2023/8/28 16:33 Jinyan.Huang Exp $
 */
@Setter
public abstract class BaseDigestLog {

    /**
     * 调用成功的字符串值
     */
    protected static final String TRUE_VALUE = "Y";

    /**
     * 调用失败的字符串值
     */
    protected static final String FALSE_VALUE = "N";

    /**
     * 调用成功的字符串描述
     */
    protected static final String TRUE_DESC = "SUCCESS";

    /**
     * 分割符
     */
    protected static final String SPLIT_TAG = ",";

    /**
     * 默认值
     */
    protected static final String DEFAULT_VALUE = "-";

    /**
     * 被调用方法
     */
    protected String invocationMethod;

    /**
     * 操作是否成功
     */
    protected boolean success;

    /**
     * 错误上下文
     */
    protected ErrorContext errorContext;

    /**
     * 操作耗时
     */
    protected long elapse;

    /**
     * 转换为摘要日志字符串。
     *
     * @return 摘要日志字符串
     */
    public String toDigestLog() {
        Map<String, Object> log = new HashMap<>();
        log.put("time", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss:SSS"));
        log.put("thread", Thread.currentThread().getName());
        {
            // 构造调用信息
            composeInvokeInfo(log);

            // 构造事务信息
            logComposeTransInfo(log);

            // 构造交易信息
            logComposeBizInfo(log);

            // 构造调用方信息
            composeCallerInfo(log);
        }


        return JsonUtil.toJsonNull(log);
    }

    /**
     * 组装事务信息
     *
     * @param log 日志信息
     */
    void logComposeTransInfo(Map<String,Object> log) {
        Map<String,Object> logInfo= new HashMap<>();
        composeTransInfo(logInfo);
        if(logInfo!=null&&logInfo.size()>0){
          log.put("transInfo",logInfo);
        }
    }

    protected void composeTransInfo(Map<String,Object> log){}

    /**
     * 组装交易信息
     *
     * @param log 日志信息
     */
    void logComposeBizInfo (Map<String,Object> log) {
        Map<String,Object> logInfo= new HashMap<>();
        composeBizInfo(logInfo);
        if(logInfo!=null&&logInfo.size()>0){
          log.put("bizInfo",logInfo);
        }
    }

    protected void composeBizInfo(Map<String,Object> log){}

    /**
     * 构造调用者信息。
     *
     * @param log 日志json map
     */
    final protected void composeCallerInfo(Map<String, Object> log) {
        String ip = TechplayStringUtil.defaultIfBlank(XFRpcUtil.getClientIp(), DEFAULT_VALUE);
        String traceId = TechplayStringUtil.defaultIfBlank(XFRpcUtil.getTraceId(), DEFAULT_VALUE);
        String clientDomain = TechplayStringUtil.defaultIfBlank(XFRpcUtil.getClientDomain(), DEFAULT_VALUE);
        log.put("clientIp", ip);
        log.put("clientName", clientDomain);
        log.put("traceId", traceId);
    }

    /**
     * 构造调用信息。
     *
     * @param log 日志json map
     */
    final protected void composeInvokeInfo(Map<String, Object> log) {
        String logSegment = TechplayStringUtil.defaultIfBlank(invocationMethod, DEFAULT_VALUE);
        //buffer.append(logSegment).append(SPLIT_TAG);
        log.put("invokeMethod", logSegment);

        logSegment = TechplayStringUtil.defaultIfBlank(success ? TRUE_VALUE : FALSE_VALUE, DEFAULT_VALUE);
        //buffer.append(logSegment).append(SPLIT_TAG);
        log.put("invokeResult", logSegment);

        logSegment = TechplayStringUtil.defaultIfBlank(success ? TRUE_DESC : fetchErrorDetailCode(errorContext), DEFAULT_VALUE);
        //buffer.append(logSegment).append(SPLIT_TAG);
        log.put("invokeCode", logSegment);
        //buffer.append(TechplayStringUtil.defaultIfBlank(String.valueOf(elapse), DEFAULT_VALUE));
        log.put("elapseTime(ms)", TechplayStringUtil.defaultIfBlank(String.valueOf(elapse), DEFAULT_VALUE));
    }

    //~~内部方法~~

    /**
     * 从标准错误上下文中提取错误码
     *
     * @param errorContext 标准错误上下文
     * @return 错误明细英文描述
     */
    private String fetchErrorDetailCode(ErrorContext errorContext) {

        if (errorContext == null) {
            return DEFAULT_VALUE;
        }
        return TechplayStringUtil.defaultIfBlank(errorContext.getErrCode(), DEFAULT_VALUE);
    }

    /**
     * 从标准错误上下文中提取错误明细英文描述
     *
     * @param errorContext 标准错误上下文
     * @return 错误明细英文描述
     */
    private String fetchErrorDetailDesc(ErrorContext errorContext) {

        if (errorContext == null) {
            return DEFAULT_VALUE;
        }
        return TechplayStringUtil.defaultIfBlank(errorContext.getErrDesc(), DEFAULT_VALUE);
    }
}
